import * as Cesium from 'cesium'

import type { PositionType, PositionResult } from '@/type/utils'

/**
  * @description: 抛物线构造函数（参考开源代码）
  * @param {*}
  * @return {*}
  */
export function parabola(startPosition: any, endPosition: any, height = 200, count = 50) {
  //方程 y=-(4h/L^2)*x^2+h h:顶点高度 L：横纵间距较大者
  let result = [];
  height = Math.max(+height, 100);
  count = Math.max(+count, 50);
  let diffLon = Math.abs(startPosition[0] - endPosition[0]);
  let diffLat = Math.abs(startPosition[1] - endPosition[1]);
  let L = Math.max(diffLon, diffLat);
  let dlt = L / count;
  if (diffLon > diffLat) {
    //base on lon
    let delLat = (endPosition[1] - startPosition[1]) / count;
    if (startPosition[0] - endPosition[0] > 0) {
      dlt = -dlt;
    }
    for (let i = 0; i < count; i++) {
      let h =
        height -
        (Math.pow(-0.5 * L + Math.abs(dlt) * i, 2) * 4 * height) /
        Math.pow(L, 2);
      let lon = startPosition[0] + dlt * i;
      let lat = startPosition[1] + delLat * i;
      let point = Cesium.Cartesian3.fromDegrees(lon, lat, h);
      result.push(point);
    }
  } else {
    //base on lat
    let delLon = (endPosition[0] - startPosition[0]) / count;
    if (startPosition[1] - endPosition[1] > 0) {
      dlt = -dlt;
    }
    for (let i = 0; i < count; i++) {
      let h =
        height -
        (Math.pow(-0.5 * L + Math.abs(dlt) * i, 2) * 4 * height) /
        Math.pow(L, 2);
      let lon = startPosition[0] + delLon * i;
      let lat = startPosition[1] + dlt * i;
      let point = Cesium.Cartesian3.fromDegrees(lon, lat, h);
      result.push(point);
    }
  }
  return result;
}

/**
 * 屏幕坐标转经纬度
 * @param viewer 
 * @param position 
 * @returns 
 */
export const coverCoordinate = (viewer: Cesium.Viewer, position: PositionType): PositionResult => {
  if (!position || !viewer || !(viewer instanceof Cesium.Viewer)) {
    return {
      lon: 0,
      lat: 0
    }
  }

  let cartesian = viewer.scene.globe.pick(viewer.camera.getPickRay(position), viewer.scene);
  let ellipsoid = viewer.scene.globe.ellipsoid;
  let cartographic = ellipsoid.cartesianToCartographic(cartesian);
  let lon = Cesium.Math.toDegrees(cartographic.longitude);  // 经度
  let lat = Cesium.Math.toDegrees(cartographic.latitude);   // 纬度
  return {
    lon, lat
  }
}
/**
 * 经纬度转屏幕坐标
 * @param viewer 
 * @param position 
 * @returns 
 */
export const coverLonlatToEvent = (viewer: Cesium.Viewer, position: PositionResult): PositionType => {
  if (!position || !viewer || !(viewer instanceof Cesium.Viewer)) {
    return {
      x: 0,
      y: 0
    }
  };
  let c3 = Cesium.Cartesian3.fromDegrees(position.lon, position.lat);
  //笛卡尔坐标转屏幕坐标
  let c2 = Cesium.SceneTransforms.wgs84ToWindowCoordinates(viewer.scene, c3);
  return {
    x: c2!.x,
    y: c2!.y
  }
}
/**
 * 世界坐标转经纬度
 * @param position 
 * @returns 
 */
export const worldCoverLonLat = (position: Cesium.Cartesian3) => {
  var cartographic = Cesium.Ellipsoid.WGS84.cartesianToCartographic(position);
  cartographic.longitude = Cesium.Math.toDegrees(cartographic.longitude);
  cartographic.latitude = Cesium.Math.toDegrees(cartographic.latitude);
  return cartographic;
}

/**
 * 经纬度转度分秒
 * @param degree 经度或纬度
 * @returns 
 */
export const ToDegrees = (degree:number)=>{
  const sign = degree < 0 ? '-' : '';
  degree = Math.abs(degree);
  let degrees:number = Math.floor(degree);
  let minutes:number = Math.floor((degree - degrees) * 60);
  let seconds:string = (((degree - degrees) * 60 - minutes) * 60).toFixed(4);
  
  if(Number(seconds)==60){
      minutes = Number(minutes) + 1
      seconds = 0 + ''
  }

  if(Number(minutes) == 60){
      degrees = Number(degrees)+1
      minutes = 0
  }

  return sign + degrees + '°' + minutes + "′" + seconds + "″";
}

/**
 * 度分秒转经纬度
 * @param dms 
 * @returns 
 */
export const ToDigital = (dms:string)=>{
  const parts = dms.match(/^(\d+)(°|'|"|′|″)?\s*(\d+)(°|'|"|′|″|\s)?(\d+(?:\.\d+)?)(°|'|"|′|″)?/);
  if (parts === null) return null;
  const dir = dms.substring(-1) === 'W' || dms.substring(-1) === 'S' ? -1 : 1;
  const degrees = parseInt(parts[1], 10);
  const minutes = parseInt(parts[3], 10);
  const seconds = parseFloat(parts[5]) || 0;

  return dir * Number((degrees + Number((minutes / 60).toFixed(6)) + Number((seconds / 3600).toFixed(6))).toFixed(6)+0);
} 

